﻿#pragma once

#include "SF2Instrument.h"
#include "SF2Layer.h"
#include "SF2Sample.h"
#include "array/Array.hpp"
#include "soundbank/ModelByteBuffer.h"
#include "soundbank/Soundbank.h"
#include "util/RIFFReader.h"
#include "util/RIFFWriter.h"
#include "yzrutil.h"

namespace yzrilyzr_soundbank{
	ECLASS(SF2Soundbank, public Soundbank){
	private:
		// The Sample Data loaded from the SoundFont
	std::shared_ptr<ModelByteBuffer> sampleData;
	std::shared_ptr<ModelByteBuffer> sampleData24;
	yzrilyzr_io::File * sampleFile=nullptr;
	bool largeFormat=false;
	public:
	yzrilyzr_collection::ArrayList<std::shared_ptr<SF2Instrument>> instruments;
	yzrilyzr_collection::ArrayList<std::shared_ptr<SF2Layer>> layers;
	yzrilyzr_collection::ArrayList<std::shared_ptr<SF2Sample>> samples;
	// version of the Sound Font RIFF file
	int32_t major=2;
	int32_t minor=1;
	// target Sound Engine
	yzrilyzr_lang::String targetEngine;
	// Sound Font Bank Name
	yzrilyzr_lang::String name;
	// Sound ROM Name
	yzrilyzr_lang::String romName;
	// Sound ROM Version
	int32_t romVersionMajor=-1;
	int32_t romVersionMinor=-1;
	// Date of Creation of the Bank
	yzrilyzr_lang::String creationDate;
	// Sound Designers and Engineers for the Bank
	yzrilyzr_lang::String engineers;
	// Product for which the Bank was intended
	yzrilyzr_lang::String product;
	// Copyright message
	yzrilyzr_lang::String copyright;
	// Comments
	yzrilyzr_lang::String comments;
	// The SoundFont tools used to create and alter the bank
	yzrilyzr_lang::String tools;
	public:
	SF2Soundbank();
	~SF2Soundbank();
	SF2Soundbank(yzrilyzr_io::File & file);
	SF2Soundbank(yzrilyzr_io::InputStream & inputstream);
	void save(const yzrilyzr_lang::String & name);
	void writeSoundbank(yzrilyzr_util::RIFFWriter & writer);
	void writeInfo(yzrilyzr_util::RIFFWriter & writer);
	void writeSdtaChunk(yzrilyzr_util::RIFFWriter & writer);
	void writePdtaChunk(yzrilyzr_util::RIFFWriter & writer);
	void writeInfoStringChunk(yzrilyzr_util::RIFFWriter & writer, const yzrilyzr_lang::String & name, const yzrilyzr_lang::String & value);
	void writeModulators(yzrilyzr_util::RIFFWriter & writer, yzrilyzr_collection::ArrayList<SF2Modulator> &modulators);
	void writeGenerators(yzrilyzr_util::RIFFWriter & writer, yzrilyzr_collection::HashMap<int32_t, int16_t> &generators);
	void save(yzrilyzr_io::File & file);
	void save(yzrilyzr_io::OutputStream & out);
	yzrilyzr_lang::String getName()const override;
	void setName(const yzrilyzr_lang::String & s);
	yzrilyzr_lang::String getVersion()const override;
	yzrilyzr_lang::String getVendor()const override;
	void setVendor(const yzrilyzr_lang::String & s);
	yzrilyzr_lang::String getDescription()const override;
	void setDescription(const yzrilyzr_lang::String & s);
	std::vector<std::shared_ptr<SoundbankResource>> getResources()override;
	std::vector<std::shared_ptr<Instrument>> getInstruments()override;
	std::shared_ptr<Instrument> getInstrument(int32_t program, int32_t bank)override;
	yzrilyzr_array::Array<std::shared_ptr<SF2Layer>> getLayers();
	yzrilyzr_array::Array<std::shared_ptr<SF2Sample>> getSamples();
	yzrilyzr_lang::String getCreationDate();
	void setCreationDate(const yzrilyzr_lang::String & creationDate);
	yzrilyzr_lang::String getProduct();
	void setProduct(const yzrilyzr_lang::String & product);
	yzrilyzr_lang::String getRomName();
	void setRomName(const yzrilyzr_lang::String & romName);
	int getRomVersionMajor();
	void setRomVersionMajor(int romVersionMajor);
	int getRomVersionMinor();
	void setRomVersionMinor(int romVersionMinor);
	yzrilyzr_lang::String getTargetEngine();
	void setTargetEngine(const yzrilyzr_lang::String & targetEngine);
	yzrilyzr_lang::String getTools();
	void setTools(const yzrilyzr_lang::String & tools);
	void addResource(std::shared_ptr < SoundbankResource > resource);
	ModelByteBuffer * getSampleData();
	void removeResource(std::shared_ptr < SoundbankResource >resource);
	void addInstrument(std::shared_ptr < SF2Instrument > resource);
	void removeInstrument(std::shared_ptr < SF2Instrument > resource);
	private:
	void readSoundbank(yzrilyzr_io::InputStream & inputstream);
	void readInfoChunk(yzrilyzr_util::RIFFReader & riff);
	void readSdtaChunk(yzrilyzr_util::RIFFReader & riff);
	void readPdtaChunk(yzrilyzr_util::RIFFReader & riff);
	};
}
